package com.liuyk.activity;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.Bundle;
import android.util.Log;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

import dalvik.system.DexClassLoader;

/**
 * 启动插件,用来装载Fragment
 * Created by Administrator on 2015/8/25.
 */
public class PluginsActivity extends Activity {

    private DexClassLoader mDexClassLoader;

    /**
     * 要启动的插件,实现约定好的路径,也就是我们的插件应用包名,下的activity或者Fragment
     */
    private String mTargetFragment;

    /**
     * plugins所在路径
     */
    private String mDexPath;
    /**
     * 解析后的存放路径
     */
    private String mToPath;

    private Resources mResource;
    private AssetManager mAssetManager;
    private Resources.Theme mTheme;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = getIntent();
        //插件所在路径
        String savePath = intent.getStringExtra("currentPath");
        //点击启动的目标fragment
        mTargetFragment = intent.getStringExtra("pluginsFragment");
        Log.i("value","Fragment:"+mTargetFragment);

        switchPath(savePath);

        /**
         * 1.如何调用目标Fragment
         *      使用自己的ClassLoader
         * 2.如何加载apk里面的资源和布局
         *      系统是通过AssetManager来加载的,所以我们要使用自己的AssetManager
         * 3.class的加载:apk ->dex ->resource
         * 4.所有的资源都在Resource类中,我们可以把plugins中的所以resource转移到当前APP中
         */
        mDexClassLoader = new DexClassLoader(//将apk或者jar里面的dex文件解析
                mDexPath,//dex文件的路径,只能从应用目录加载
                mToPath,//解析后的dex文件,存放路径
                null,//C或C++底层库
                getClassLoader());

        //将plugins中的Resource转移到APP中
        switchResource();
        //开始加载plugins里面的Fragment
        loaderFragment();

//        loaderImage();
    }

    /**
     * 将plugins中的Resource转移到APP中
     */
    private void switchResource() {
        try {
            mAssetManager = AssetManager.class.newInstance();
            //资源转移
            mAssetManager.getClass().getMethod("addAssetPath", String.class).invoke(
                    mAssetManager, mDexPath);
            mResource = new Resources(mAssetManager, getResources().getDisplayMetrics(),
                    getResources().getConfiguration());

            mTheme = mResource.newTheme();
            mTheme.setTo(super.getTheme());//将当前主题设置到newTheme()

        } catch (InvocationTargetException e) {
            Log.i("value", "InvocationTargetException");
        } catch (NoSuchMethodException e) {
            Log.i("value", "NoSuchMethodException");
        } catch (IllegalAccessException e) {
            Log.i("value", "IllegalAccessException");
        } catch (InstantiationException e) {
            Log.i("value", "InstantiationException");
        }

    }

    @SuppressWarnings("ResourceType")
    private void loaderFragment() {
        FrameLayout frameLayout = new FrameLayout(this);
        frameLayout.setLayoutParams(new FrameLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
        ));
        frameLayout.setId(1);
        setContentView(frameLayout);
        //将Fragment添加到FrameLayout中
        Fragment fragment;
        try {
            fragment = (Fragment) mDexClassLoader.loadClass(mTargetFragment).newInstance();
            FragmentManager fm = getFragmentManager();
            FragmentTransaction transaction = fm.beginTransaction();
            transaction.add(1, fragment);
            transaction.commit();
        } catch (ClassNotFoundException e) {
            Log.i("value", "ClassNotFoundException");
        } catch (Exception e) {
            Log.i("value", "Exception");
        }

    }

    @SuppressWarnings("deprecation")
    private void loaderImage(){
        final String packageName = "com.example.pluginsapp";
        try {
            final Context pluginsContext = createPackageContext(packageName,
                    CONTEXT_IGNORE_SECURITY|CONTEXT_INCLUDE_CODE);
            ImageView imageView = new ImageView(this);
            imageView.setLayoutParams(new FrameLayout.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
            ));

            Class<?> clazz = mDexClassLoader.loadClass(packageName + ".R$drawable");
            Field[] fields = clazz.getFields();
            for(Field field : fields){
                if(field.getName().contains("bg")){
                    Log.i("value","fieldName:" + field.getName());

                    int resId = pluginsContext.getResources().getIdentifier(
                            field.getName(),"drawable",packageName);
                    Log.i("value","resId:" + resId);
                    imageView.setBackgroundDrawable(pluginsContext.getResources().getDrawable(resId));
                    setContentView(imageView);
                }
            }

        } catch (ClassNotFoundException e) {
            Log.i("value","ClassNotFoundException");
        } catch (Exception e){
            Log.i("value","Exception");
        }
    }

    /**
     * 将下载的apk路径,转移到应用目录下
     *
     * @param savePath 下载的apk路径
     */
    private void switchPath(String savePath) {
        final File saveFile = new File(savePath);
        File appFile = new File(getFilesDir(), "dex");//要转移到的应用目录路径
        appFile.mkdir();
        appFile = new File(appFile, saveFile.getName());

        final File pluginsFile = new File(getFilesDir(), "dexOut");//解析后存放目录
        pluginsFile.mkdir();

        InputStream in;
        OutputStream out;
        try {
            in = new FileInputStream(saveFile);
            out = new FileOutputStream(appFile);

            byte[] buff = new byte[in.available()];
            in.read(buff);

            out.write(buff);//写进应用目录

            in.close();
            out.close();

            mDexPath = appFile.getAbsolutePath();
            mToPath = pluginsFile.getAbsolutePath();

            Log.i("value","DexPath:" + mDexPath);
            Log.i("value","mToPath:" + mToPath);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException ioe) {
            Log.i("value", "IOException");
        }
    }

    @Override
    public ClassLoader getClassLoader() {//activity就是通过调用这个方法,来拿到类加载器
        return mDexClassLoader == null ? super.getClassLoader() : mDexClassLoader;
    }

    @Override
    public AssetManager getAssets() {
        return mAssetManager == null ? super.getAssets() : mAssetManager;
    }

    @Override
    public Resources getResources() {
        return mResource == null ? super.getResources() : mResource;
    }

    @Override
    public Resources.Theme getTheme() {
        return mTheme == null ? super.getTheme() : mTheme;
    }

}
